#pragma once

#include <exception>
#include "StdString.h"
#include "stdarg.h"

class CCustomException: public std::exception
{
public:
	CCustomException();
	CCustomException(DWORD dwCode): m_dwErrorCode(dwCode)
	{
		m_strError.Format(_T("%d"), dwCode);
	};
	CCustomException( const TCHAR* szFmt, ...): m_dwErrorCode(-1)
	{
		va_list argList;
		va_start(argList, szFmt);
		m_strError.FormatV(szFmt, argList);
		va_end(argList);
	};
	CCustomException( DWORD dwSysErrorCode, const TCHAR* szFmt, ...): m_dwErrorCode(-1)
	{
		va_list argList;
		va_start(argList, szFmt);
		m_strError.FormatV(szFmt, argList);

#if defined(_MSC_VER)
		LPVOID lpMsgBuf;
		::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL, dwSysErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
		m_strError += (LPCTSTR)lpMsgBuf;
		LocalFree(lpMsgBuf);
#endif
		va_end(argList);
	};

#if !defined(_MSC_VER) 
	virtual ~CCustomException() throw()
	{

	}
#endif


	DWORD	GetErrorCode() const {
		return m_dwErrorCode; };

	LPCTSTR GetErrorStr() const {
		return m_strError; };

	operator LPCTSTR () const {
		return m_strError; }

	operator const std::exception&() const {
		return *this; }

#if !defined(_MSC_VER)
		virtual const char* what() const throw()
		{
			m_strAError = m_strError;
			return m_strAError;
		}
#else
	virtual const char * __CLR_OR_THIS_CALL what() const 
	{
		m_strAError = (LPCSTR)(_bstr_t)m_strError;
		return m_strAError;
	}
#endif

protected:
	DWORD					m_dwErrorCode;
	CStdString				m_strError;
	mutable CStdStringA		m_strAError;
};

